package org.aman.generator.modify;

import static org.mybatis.generator.internal.util.JavaBeansUtil.getCamelCaseString;
import static org.mybatis.generator.internal.util.JavaBeansUtil.getGetterMethodName;
import static org.mybatis.generator.internal.util.JavaBeansUtil.getSetterMethodName;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.aman.generator.plugin.AmanPluginConfig;
import org.aman.generator.util.JavaFileLine;
import org.aman.generator.util.JavaFileUtil;
import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.dom.OutputUtilities;
import org.mybatis.generator.api.dom.java.Field;
import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType;
import org.mybatis.generator.api.dom.java.Method;
import org.mybatis.generator.api.dom.java.Parameter;
import org.mybatis.generator.api.dom.java.TopLevelClass;
import org.mybatis.generator.codegen.mybatis3.model.BaseRecordGenerator;
import org.mybatis.generator.internal.util.JavaBeansUtil;

/**
 * @desc <p></p>
 * @author DaiJiangGuo
 * @date 2015年5月13日下午1:02:46
 */
public class ExtendsBaseRecordGenerator extends BaseRecordGenerator{
    private AmanPluginConfig apc;

    public ExtendsBaseRecordGenerator(AmanPluginConfig apc) {
        super();
        this.apc = apc;
        this.setContext(apc.context);
        this.setIntrospectedTable(apc.introspectedTable);
        initialized();
    }

    public void initialized() {

    }

    /**
     * @author DaiJiangGuo
     * @data 2015年5月13日 下午1:04:55
     * @param property
     * @param targetFile
     * @param introspectedTable
     * @param topLevelClass
     * @throws IOException
     */
    public void addColumns(String property, File targetFile, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) throws IOException {
        String[] cols = property.split(",");
        if(cols == null || cols.length == 0){//加列空
            return ;
        }

        List<IntrospectedColumn> introCols = introspectedTable.getAllColumns();
        if(introCols == null || introCols.isEmpty()){//数据库无列
            return ;
        }

        JavaFileUtil javaFile = new JavaFileUtil(targetFile, topLevelClass.getType());
        List<JavaFileLine> lines = javaFile.parse();

        List<Field> fieldList = new ArrayList<Field>();
        List<Method> getterList = new ArrayList<Method>();
        List<Method> setterList = new ArrayList<Method>();
        Set<String> addImportList = new HashSet<String>();

        for(String col : cols) {
            IntrospectedColumn addcol = null;
            boolean find = false;
            for(IntrospectedColumn intro : introCols){//数据库列
                if(intro.getActualColumnName().equals(col)){
                    addcol = intro;
                    find = true;
                    break;
                }
            }
            if(!find){
                continue;
            }

            Field field = JavaBeansUtil.getJavaBeansField(addcol, this.context, this.introspectedTable);
            fieldList.add(field);
            addImportList.addAll(field.getType().getImportList());

            Method getter = JavaBeansUtil.getJavaBeansGetter(addcol, this.context, this.introspectedTable);
            getterList.add(getter);
            addImportList.addAll(getter.getReturnType().getImportList());
            List<Parameter> getterParam = getter.getParameters();
            for(Parameter p : getterParam) {
                addImportList.addAll(p.getType().getImportList());
            }

            Method setter = JavaBeansUtil.getJavaBeansSetter(addcol, this.context, this.introspectedTable);
            setterList.add(setter);
            if(setter.getReturnType() != null){
                addImportList.addAll(setter.getReturnType().getImportList());
            }
            List<Parameter> setterParam = setter.getParameters();
            for(Parameter p : setterParam) {
                addImportList.addAll(p.getType().getImportList());
            }
        }

        StringBuilder sb = new StringBuilder();
        Map<String, Integer> map = javaFile.getAddColumnInfo();
        Integer lastImportLine = map.get("lastImportLine");
        Integer lastFieldLine = map.get("lastFieldLine");
        Integer lastMethodLine = map.get("lastMethodLine");

        for(int i=0;i<lines.size();i++) {
            JavaFileLine line = lines.get(i);

            if (i == lastImportLine + 1) {// 加在最后一行import的下一行前面
                // 添加import
                for (String im : addImportList) {
                    if (!javaFile.getImportList().contains(im)) {
                        sb.append("import " + im + ";");
                        OutputUtilities.newLine(sb);
                    }
                }
            }
            if (i == lastFieldLine + 1) {//最后一个属性的下一行的前面
                for(Field f: fieldList){
                    if(!javaFile.getFieldList().contains(f.getName())){
                        OutputUtilities.newLine(sb);//前面留一行
                        sb.append(f.getFormattedContent(1, null));
                        OutputUtilities.newLine(sb);
                    }
                }
            }
            if (i == lastMethodLine + 1) {//最后一个方法的下一行的前面
                for(Method f: getterList){
                    OutputUtilities.newLine(sb);//前面留一行
                    sb.append(f.getFormattedContent(1, false, null));
                    OutputUtilities.newLine(sb);
                }
                for(Method f: setterList){
                    OutputUtilities.newLine(sb);//前面留一行
                    sb.append(f.getFormattedContent(1, false, null));
                    OutputUtilities.newLine(sb);
                }
            }

            sb.append(line.getContent());
            if(i < lines.size()-1){//not last line
                OutputUtilities.newLine(sb);
            }
        }


        BufferedWriter bw = new BufferedWriter(new FileWriter(targetFile, false));
        bw.write(sb.toString());
        bw.close();
    }


    /**
     * @author DaiJiangGuo
     * @data 2015年5月13日 下午1:05:04
     * @param property
     * @param targetFile
     * @param introspectedTable
     * @param topLevelClass
     * @throws IOException
     */
    public void updColumns(String property, File targetFile, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) throws IOException {
        String[] cols = property.split(",");
        if(cols == null || cols.length == 0){//加列空
            return ;
        }

        List<IntrospectedColumn> introCols = introspectedTable.getAllColumns();
        if(introCols == null || introCols.isEmpty()){//数据库无列
            return ;
        }

        JavaFileUtil javaFile = new JavaFileUtil(targetFile, topLevelClass.getType());
        List<JavaFileLine> lines = javaFile.parse();

        Map<String, Field> updFieldMap = new HashMap<String, Field>();
        Map<String, Method> updGetterMap = new HashMap<String, Method>();
        Map<String, Method> updSetterMap = new HashMap<String, Method>();
        List<String> addimportList = new ArrayList<String>();
        for(String col : cols){
            String[] updInfo = col.split(":");
            if(updInfo!=null && updInfo.length==2){
                String oldFiledName = getCamelCaseString(updInfo[0], false);
                String oldSetterName = getSetterMethodName(oldFiledName);
                String oldGetterName = getGetterMethodName(oldFiledName, new FullyQualifiedJavaType("Object"));
                if(!javaFile.getMethodList().contains(oldGetterName)){
                    oldGetterName = "is" + oldGetterName.substring(oldGetterName.indexOf("get")+3);
                }
                if(!javaFile.getMethodList().contains(oldGetterName)){
                    oldGetterName = "is" + oldGetterName.substring(oldGetterName.indexOf("getIs")+5);
                }

                IntrospectedColumn newIntro = null;
                for(IntrospectedColumn intro : introCols){
                    if(intro.getActualColumnName().equalsIgnoreCase(updInfo[1])){
                        newIntro = intro;
                        break;
                    }
                }

                if(newIntro == null){
                    continue;
                }

                addimportList.addAll(newIntro.getFullyQualifiedJavaType().getImportList());

                Field field = JavaBeansUtil.getJavaBeansField(newIntro, this.context, this.introspectedTable);
                updFieldMap.put(oldFiledName, field);
                addimportList.addAll(field.getType().getImportList());

                Method getter = JavaBeansUtil.getJavaBeansGetter(newIntro, this.context, this.introspectedTable);
                updGetterMap.put(oldGetterName, getter);
                addimportList.addAll(getter.getReturnType().getImportList());
                List<Parameter> getterParam = getter.getParameters();
                for(Parameter p : getterParam) {
                    addimportList.addAll(p.getType().getImportList());
                }

                Method setter = JavaBeansUtil.getJavaBeansSetter(newIntro, this.context, this.introspectedTable);
                updSetterMap.put(oldSetterName, setter);
                if(setter.getReturnType() != null){
                    addimportList.addAll(setter.getReturnType().getImportList());
                }
                List<Parameter> setterParam = setter.getParameters();
                for(Parameter p : setterParam) {
                    addimportList.addAll(p.getType().getImportList());
                }
            }
        }

        List<String> dels = new ArrayList<String>();
        StringBuilder sb = new StringBuilder();
        for(int i=0;i<lines.size();i++) {
            JavaFileLine line = lines.get(i);
            boolean needAppend = true;
            if("import".equals(line.getType())){
                if(i+1<lines.size() && "class".equals(lines.get(i+1).getType())){//import最后行
                    if(addimportList != null && !addimportList.isEmpty()){//需要加import
                        sb.append(line.getContent());
                        OutputUtilities.newLine(sb);//最后import

                        //添加import
                        for(String im : addimportList){
                            if(!javaFile.getImportList().contains(im)){
                                sb.append("import " + im + ";");
                                OutputUtilities.newLine(sb);
                            }
                        }
                        needAppend = false;
                    }
                }
            }

            if("field".equals(line.getType())) {
                if(dels.contains("field-"+line.getForObj())){//需要删除的
                    needAppend = false;
                } else if(updFieldMap.containsKey(line.getForObj())){//修改属性
                    needAppend = false;

                    Field f = updFieldMap.get(line.getForObj());
                    OutputUtilities.newLine(sb);//前面留一行
                    sb.append(f.getFormattedContent(1, null));
                    OutputUtilities.newLine(sb);

                    dels.add("field-"+line.getForObj());
                }
            }
            if("method".equals(line.getType())) {
                if(dels.contains("method-"+line.getForObj())){//需要删除的
                    needAppend = false;
                } else if(updGetterMap.containsKey(line.getForObj())){//修改属性
                    needAppend = false;

                    Method m = updGetterMap.get(line.getForObj());
                    OutputUtilities.newLine(sb);//前面留一行
                    sb.append(m.getFormattedContent(1, false, null));
                    OutputUtilities.newLine(sb);

                    dels.add("method-"+line.getForObj());
                } else if(updSetterMap.containsKey(line.getForObj())){//修改属性
                    needAppend = false;

                    Method m = updSetterMap.get(line.getForObj());
                    OutputUtilities.newLine(sb);//前面留一行
                    sb.append(m.getFormattedContent(1, false, null));
                    OutputUtilities.newLine(sb);

                    dels.add("method-"+line.getForObj());
                }
            }

            if(needAppend){
                sb.append(line.getContent());
                if(i < lines.size()-1){//not last line
                    OutputUtilities.newLine(sb);
                }
            }
        }


        BufferedWriter bw = new BufferedWriter(new FileWriter(targetFile, false));
        bw.write(sb.toString());
        bw.close();
    }

    /**
     * @author DaiJiangGuo
     * @data 2015年5月13日 下午1:05:11
     * @param property
     * @param targetFile
     * @param introspectedTable
     * @param topLevelClass
     * @throws SecurityException
     * @throws NoSuchFieldException
     * @throws IOException
     */
    public void delColumns(String property, File targetFile, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) throws NoSuchFieldException, SecurityException, IOException {
        String[] cols = property.split(",");
        if(cols == null || cols.length == 0){//加列空
            return ;
        }
        JavaFileUtil javaFile = new JavaFileUtil(targetFile, topLevelClass.getType());
        List<JavaFileLine> lines = javaFile.parse();

        List<String> fieldList = new ArrayList<String>();
        List<String> getterList = new ArrayList<String>();
        List<String> setterList = new ArrayList<String>();
        for(String col : cols) {
            String filedName = getCamelCaseString(col, false);
            String setterName = getSetterMethodName(filedName);
            String getterName = getGetterMethodName(filedName, new FullyQualifiedJavaType("Object"));
            if(!javaFile.getMethodList().contains(getterName)){//boolean基本类型
                getterName = "is" + getterName.substring(getterName.indexOf("get")+3);
            }

            fieldList.add(filedName);
            getterList.add(getterName);
            setterList.add(setterName);
        }

        StringBuilder sb = new StringBuilder();
        for(int i=0;i<lines.size();i++){
            JavaFileLine line = lines.get(i);
            boolean del = false;
            if("field".equals(line.getType())){
                if(fieldList.contains(line.getForObj())){//删除行 包含这行
                    del = true;
                }
            }
            if("method".equals(line.getType())){
                if(getterList.contains(line.getForObj())){//删除行 包含这行
                    del = true;
                }
                if(setterList.contains(line.getForObj())){//删除行 包含这行
                    del = true;
                }
            }
            if(!del){
                sb.append(line.getContent());
                if(i < lines.size()-1){//not last line
                    OutputUtilities.newLine(sb);
                }
            }
        }

        BufferedWriter bw = new BufferedWriter(new FileWriter(targetFile, false));
        bw.write(sb.toString());
        bw.close();
    }

    /**
     * @author DaiJiangGuo
     * @data 2015年5月13日 下午1:12:00
     * @param targetFile
     * @param topLevelClass
     * @param introspectedTable
     * @return
     */
    public boolean matcherUpdColums(File targetFile, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
        /*
         * 只做数据库填加列后 加属性
         * 数据库减少列 不能判断。因为bean的属性可以多于数据库列
         * 
         */

        return false;
    }

    public void addColumns(List<IntrospectedColumn> needAddCols, File targetFile, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) throws IOException {
        JavaFileUtil javaFile = new JavaFileUtil(targetFile, topLevelClass.getType());
        List<JavaFileLine> lines = javaFile.parse();

        List<Field> fieldList = new ArrayList<Field>();
        Set<String> addImportList = new HashSet<String>();

        if(!addImportList.contains("javax.persistence.Column")){
            addImportList.addAll(new FullyQualifiedJavaType("javax.persistence.Column").getImportList());
        }
        if(!addImportList.contains("javax.persistence.Id")){
            addImportList.addAll(new FullyQualifiedJavaType("javax.persistence.Id").getImportList());
        }
        if(!addImportList.contains("javax.persistence.Table")){
            addImportList.addAll(new FullyQualifiedJavaType("javax.persistence.Table").getImportList());
        }
        if(!addImportList.contains("javax.persistence.GeneratedValue")){
            addImportList.addAll(new FullyQualifiedJavaType("javax.persistence.GeneratedValue").getImportList());
        }
        
        for(IntrospectedColumn addcol : needAddCols) {
            Field field = JavaBeansUtil.getJavaBeansField(addcol, this.context, this.introspectedTable);
            if(apc.isPkCol(this.introspectedTable.getPrimaryKeyColumns(), addcol) && addcol.isAutoIncrement()){
                addImportList.addAll(new FullyQualifiedJavaType("javax.persistence.GeneratedValue").getImportList());
                field.addAnnotation("@GeneratedValue(generator = \"JDBC\")");
            }
            fieldList.add(field);
            addImportList.addAll(field.getType().getImportList());
        }

        StringBuilder sb = new StringBuilder();
        Map<String, Integer> map = javaFile.getAddColumnInfo();
        Integer lastImportLine = map.get("lastImportLine");
        Integer lastFieldLine = map.get("lastFieldLine");
        
        for(int i=0;i<lines.size(); i++) {
            JavaFileLine line = lines.get(i);

            if (i == lastImportLine + 1) {// 加在最后一行import的下一行前面
                // 添加import
                for (String im : addImportList) {
                    if (!javaFile.getImportList().contains(im)) {
                        sb.append("import " + im + ";");
                        OutputUtilities.newLine(sb);
                    }
                }
            }
            if (i == lastFieldLine + 1) {//最后一个属性的下一行的前面
                for(Field f: fieldList){
                    if(!javaFile.getFieldList().contains(f.getName())){
                        OutputUtilities.newLine(sb);//前面留一行
                        sb.append(f.getFormattedContent(1, null));
                        OutputUtilities.newLine(sb);
                    }
                }
            }
            
            sb.append(line.getContent());
            if(i < lines.size()-1){//not last line
                OutputUtilities.newLine(sb);
            }
        }
        
        BufferedWriter bw = new BufferedWriter(new FileWriter(targetFile, false));
        bw.write(sb.toString());
        bw.close();
    }

    public void updTypeColumns(List<IntrospectedColumn> needUpdCols, File targetFile, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) throws IOException {
        JavaFileUtil javaFile = new JavaFileUtil(targetFile, topLevelClass.getType());
        List<JavaFileLine> lines = javaFile.parse();

        Map<String, Field> updFieldMap = new HashMap<String, Field>();
        List<String> addimportList = new ArrayList<String>();
        if(!addimportList.contains("javax.persistence.Column")){
            addimportList.addAll(new FullyQualifiedJavaType("javax.persistence.Column").getImportList());
        }
        if(!addimportList.contains("javax.persistence.Id")){
            addimportList.addAll(new FullyQualifiedJavaType("javax.persistence.Id").getImportList());
        }
        if(!addimportList.contains("javax.persistence.Table")){
            addimportList.addAll(new FullyQualifiedJavaType("javax.persistence.Table").getImportList());
        }
        if(!addimportList.contains("javax.persistence.GeneratedValue")){
            addimportList.addAll(new FullyQualifiedJavaType("javax.persistence.GeneratedValue").getImportList());
        }
        
        for(IntrospectedColumn dbCol : needUpdCols) {
            Field newField = JavaBeansUtil.getJavaBeansField(dbCol, this.context, this.introspectedTable);
            if(apc.isPkCol(this.introspectedTable.getPrimaryKeyColumns(), dbCol) && dbCol.isAutoIncrement()){
                addimportList.addAll(new FullyQualifiedJavaType("javax.persistence.GeneratedValue").getImportList());
                newField.addAnnotation("@GeneratedValue(generator = \"JDBC\")");
            }
            updFieldMap.put(dbCol.getJavaProperty(), newField);
            addimportList.addAll(dbCol.getFullyQualifiedJavaType().getImportList());
            addimportList.addAll(newField.getType().getImportList());
        }

        List<String> dels = new ArrayList<String>();
        StringBuilder sb = new StringBuilder();
        for(int i=0;i<lines.size();i++) {
            JavaFileLine line = lines.get(i);
            boolean needAppend = true;
            if("import".equals(line.getType())){
                if(i+1<lines.size() && "class".equals(lines.get(i+1).getType())){//import最后行
                    if(addimportList != null && !addimportList.isEmpty()){//需要加import
                        sb.append(line.getContent());
                        OutputUtilities.newLine(sb);//最后import

                        //添加import
                        for(String im : addimportList){
                            if(!javaFile.getImportList().contains(im)){
                                sb.append("import " + im + ";");
                                OutputUtilities.newLine(sb);
                            }
                        }
                        needAppend = false;
                    }
                }
            }

            if("field".equals(line.getType())) {
                if(dels.contains("field-"+line.getForObj())){//需要删除的
                    needAppend = false;
                } else if(updFieldMap.containsKey(line.getForObj())){//修改属性
                    needAppend = false;

                    Field f = updFieldMap.get(line.getForObj());
                    OutputUtilities.newLine(sb);//前面留一行
                    sb.append(f.getFormattedContent(1, null));
                    OutputUtilities.newLine(sb);

                    dels.add("field-"+line.getForObj());
                }
            }
            if(needAppend){
                sb.append(line.getContent());
                if(i < lines.size()-1){//not last line
                    OutputUtilities.newLine(sb);
                }
            }
        }

        BufferedWriter bw = new BufferedWriter(new FileWriter(targetFile, false));
        bw.write(sb.toString());
        bw.close();
    }

    /**
     * @author DaiJiangGuo
     * @data 2015年5月13日 下午1:05:11
     * @param fieldNameList
     * @param targetFile
     * @param topLevelClass
     * @throws SecurityException
     * @throws NoSuchFieldException
     * @throws IOException
     */
    public void delColumns(List<String> fieldNameList, File targetFile, TopLevelClass topLevelClass) throws NoSuchFieldException, SecurityException, IOException {
        JavaFileUtil javaFile = new JavaFileUtil(targetFile, topLevelClass.getType());
        List<JavaFileLine> lines = javaFile.parse();
        StringBuilder sb = new StringBuilder();
        for(int i=0;i<lines.size();i++){
            JavaFileLine line = lines.get(i);
            boolean del = false;
            if("field".equals(line.getType())){
                if(fieldNameList.contains(line.getForObj())){//删除行 包含这行
                    del = true;
                }
            }
            if(!del){
                sb.append(line.getContent());
                if(i < lines.size()-1){//not last line
                    OutputUtilities.newLine(sb);
                }
            }
        }

        BufferedWriter bw = new BufferedWriter(new FileWriter(targetFile, false));
        bw.write(sb.toString());
        bw.close();
    }

}
